﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ElasticPropertyPath.Core;

namespace ElasticPropertyPath.Test
{

    public class FakeClass
    {
        public Type T;
        public string Name;

        public object R;
        public object self
        {
            get
            {
                return new FakeClass();
            }
        }

        public Type[] types;

        public static string sName = "sd";

        public FakeClass()
        {
            T = typeof(string);
            R = typeof(int);

            types = new Type[] { T };
        }

        public string FromInside1()
        {
            return PropertyPathExtractor.PropertyPath(() => this.Name);
        }

        public string FromInside2()
        {
            return PropertyPathExtractor.PropertyPath(() => Name);
        }
    }

    [TestClass]
    public class PropertyPathFixture
    {
        [TestMethod]
        public void Basic()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyPath(() => fake.Name);

            Assert.AreEqual<string>("fake.Name", computed);
        }

        [TestMethod]
        public void FromInside1()
        {
            FakeClass fake = new FakeClass();
            string computed = fake.FromInside1();

            Assert.AreEqual<string>("Name", computed);
        }

        [TestMethod]
        public void FromInside2()
        {
            FakeClass fake = new FakeClass();
            string computed = fake.FromInside2();

            Assert.AreEqual<string>("Name", computed);
        }

        [TestMethod]
        public void Complex()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyPath(() => fake.T.Name.Length);

            Assert.AreEqual<string>("fake.T.Name.Length", computed);
        }

        [TestMethod]
        public void Value()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyValue(() => fake.T.Name);

            Assert.AreEqual<string>("String", computed);
        }


        [TestMethod]
        public void Type()
        {
            FakeClass fake = new FakeClass();
            var computed = PropertyPathExtractor.PropertyType(() => fake.T.Name.Length);

            Assert.AreEqual<Type>(typeof(int), computed);
        }


        [TestMethod]
        public void BasicConversion()
        {
            FakeClass fake = new FakeClass();
            var computed = PropertyPathExtractor.PropertyPath(() => ((Type)fake.R).Name);

            Assert.AreEqual<string>("fake.R.Name", computed);
        }


        [TestMethod]
        public void ComplextConversion()
        {
            FakeClass fake = new FakeClass();
            var computed = PropertyPathExtractor.PropertyPath(() => (((FakeClass)((FakeClass)fake.self).self).T));

            Assert.AreEqual<string>("fake.self.self.T", computed);
        }


        [TestMethod]
        public void Local()
        {
            FakeClass fake = new FakeClass();

            string s = null;

            var computed = PropertyPathExtractor.PropertyPath(() => s);

            Assert.AreEqual<string>("s", computed);
        }


        [TestMethod, ExpectedException(typeof(Exception))]
        public void WrongExpression()
        {
            FakeClass f = new FakeClass();
            var computed = PropertyPathExtractor.PropertyPath(() => f.T == f.T);
        }


        [TestMethod]
        public void Index()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyPath(() => fake.types[0]);

            Assert.AreEqual<string>("fake.types[0]", computed);
        }


        [TestMethod]
        public void IndexComplex()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyPath(() => fake.types[fake.T.Name.Length]);

            Assert.AreEqual<string>("fake.types[fake.T.Name.Length]", computed);
        }

        [TestMethod]
        public void IndexConvert()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyPath(() => ((FakeClass)fake.self).types[((Type)fake.R).Name.Length]);

            Assert.AreEqual<string>("fake.self.types[fake.R.Name.Length]", computed);
        }

        [TestMethod, ExpectedException(typeof(Exception))]
        public void Static()
        {
            FakeClass fake = new FakeClass();
            string computed = PropertyPathExtractor.PropertyPath(() => FakeClass.sName);

            Assert.AreEqual<string>("FakeClass.sName", computed);
        }

        


    }
}
